<?php


namespace App\Commons\Domain\Module\Exchange\Traits;

use App\Commons\Domain\Module\Exchange\Entity\AdvertisingEntity;
use App\Commons\Domain\Module\Exchange\Entity\OrderEntity;
use App\Commons\Domain\Module\Exchange\Model\Advertising;
use App\Commons\Domain\Module\Financial\Model\Payment;
use App\Commons\Domain\Module\Financial\Model\Wallet;

trait OrderTrait
{
    /**
     * 创建订单
     * @param string $uid
     * @param int $ad_id 广告id
     * @param float $quantity 数量
     * @return mixed
     */
    public function createOrder(string $uid, int $ad_id, float $quantity)
    {
        return db_trans(function () use ($quantity, $uid, $ad_id) {
            // 获取对应的广告
            $ad = Advertising::where(['id' => $ad_id])->firstOrFail();
            // 获取交易创建者的钱包
            $wallet = Wallet::where(['uid' => $uid, 'coin_id' => $ad->wallet->coin_id])->firstOrFail();

            // 订单数据：广告id、价格、数量、交易创建者uid、订单状态
            $order_data = [
                'advertising_id' => $ad->id,
                'price' => $ad->price,
                'quantity' => $quantity,
                'trader_uid' => $uid,
                'status' => 1,
                'order_no' => $this->getOrderNo()
            ];

            // 广告为买，则订单创建者为卖方，冻结卖方对应的金额，还需提供收款账户
            if ($ad->type === 2) {
                $this->ctx->FinancialService->freeze($wallet->id, $quantity);
                // 收款账户为订单创建者
                $pay_uid = $uid;
            } elseif ($ad->type === 1) {
                // 广告为卖，则将广告中的数量移入订单，广告中的数量进行相应的减少
                app(AdvertisingEntity::class)->cutAd($ad_id, $quantity);
                // 收款账户为广告创建者
                $pay_uid = $ad->uid;
            }

            $payment = Payment::where(['uid' => $pay_uid, 'type' => $ad->pay_type])->first();

            // 未绑定对应的付款方式
            throw_on(!$payment, 0xf00361);
            $order_data['payment_id'] = $payment->id;

            return app(OrderEntity::class)->createOrder($order_data);
        });
    }

    /**
     * 买方付款
     * @param string $order_no
     * @param int $payment_id
     * @return bool
     */
    public function payOrder(string $order_no, int $payment_id)
    {
        return app(OrderEntity::class)->payOrder($order_no, $payment_id);
    }

    /**
     * 卖方放币，至此订单完成，卖方钱包对应的冻结金额减少
     * @param string $uid
     * @param string $order_no
     * @return void
     */
    public function confirmOrder(string $uid, string $order_no)
    {
        return db_trans(function () use ($order_no, $uid) {
            $order = app(OrderEntity::class)->confirmOrder($uid, $order_no);
            $wallet = Wallet::where([
                'coin_id' => $order->advertising->wallet->coin_id,
                'uid' => $uid
            ])->firstOrFail();

            $this->ctx->FinancialService->cutFreeze($wallet->id, $order->quantity);

            return $order;
        });
    }

    /**
     * 取消订单
     * TODO:只有买方在未付款前或收到退款后能取消订单
     * @param string $order_no
     * @return mixed
     */
    public function cancelOrder(string $order_no)
    {
        return db_trans(function () use ($order_no) {
            $order = app(OrderEntity::class)->cancelOrder($order_no);
            app(AdvertisingEntity::class)->addAd($order->advertising->id, $order->quantity);
            return $order;
        });
    }

    /**
     * 生成订单号
     * @return string
     */
    public function getOrderNo()
    {
        $order_id_main = time() . rand(1000, 9999);
        $order_id_len = strlen($order_id_main);
        $order_id_sum = 0;
        for ($i = 0; $i < $order_id_len; $i++) {
            $order_id_sum += (int)(substr($order_id_main, $i, 1));
        }
        return 'NY' . $order_id_main . str_pad((100 - $order_id_sum % 100) % 100, 2, '0', STR_PAD_LEFT);
    }
}
